const std = @import("std");
const lib = @import("../user.zig");
const sys = @import("../syscall.zig");

const allocator = lib.heap.c_allocator;
const c_str = sys.c_str;
const Args = std.ArrayList(?c_str);

pub export fn execvp(file: c_str, argv: [*:null]const ?c_str) c_int {
    lib.execvp(file, std.mem.span(argv)) catch return -1;
    return -1;
}

pub export fn execlp(file: c_str, arg: c_str, ...) c_int {
    var ap = @cVaStart();
    defer @cVaEnd(&ap);

    var args: Args = .empty;
    defer args.deinit(allocator);

    const argv = vargv(&args, arg, &ap) catch return -1;
    return execvp(file, argv);
}

pub export fn execl(path: c_str, arg: c_str, ...) c_int {
    var ap = @cVaStart();
    defer @cVaEnd(&ap);

    var args: Args = .empty;
    defer args.deinit(allocator);

    const argv = vargv(&args, arg, &ap) catch return -1;
    return sys.exec(path, argv);
}

fn vargv(args: *Args, arg: c_str, ap: *std.builtin.VaList) ![*:null]const ?c_str {
    try args.append(allocator, arg);
    while (true) {
        const str = @cVaArg(ap, ?c_str) orelse break;
        try args.append(allocator, str);
    }
    try args.append(allocator, null);
    return @ptrCast(args.items);
}
